// -----------------------------------------------------------------------
//  <copyright file="CreateResourceCommand.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2025 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2025/1/5 13:58</last-date>
// -----------------------------------------------------------------------

using DaprPlus.Authorization.Domain;
using DaprPlus.Authorization.Domain.Entities;
using DaprPlus.Authorization.Domain.Specs;
using OSharp.Collections;

namespace DaprPlus.Authorization.Application.Commands;

[AuthConfig(typeof(Resource), ResourceAccessType.RoleLimit, "Create")]
public class CreateResourceCommand : IRequest<ApiResult>, ICommand
{
    public ResourceInDto[] Dtos { get; set; } = [];
}

public class CreateResourceCommandHandler(IResourceService service)
    : IRequestHandler<CreateResourceCommand, ApiResult>
{
    public async Task<ApiResult> Handle(CreateResourceCommand request, CancellationToken cancellationToken)
    {
        var resources = request.Dtos.Select(dto => new Resource
        {
            Name = dto.Name,
            Code = dto.Code,
            Description = dto.Description,
            ServiceName = dto.ServiceName,
            Type = dto.Type,
            AccessType = dto.AccessType,
            IsLocked = dto.IsLocked,
            IsSystem = false,
            MetadataJson = dto.Metadata == null || dto.Metadata.Count == 0 ? null : dto.Metadata.ToTextJson(),
            AllowedOperationsJson = dto.AllowedOperations == null || dto.AllowedOperations.Length == 0 ? null : dto.AllowedOperations.ToTextJson()
        }).ToArray();

        var results = new List<ApiResult>();
        foreach (var resource in resources)
        {
            var result = await service.CreateResourceAsync(resource, cancellationToken);
            results.Add(result);
        }

        if (results.All(r => r.IsSuccess()))
        {
            return ApiResult.Success($"资源 {resources.Select(m => m.Name).ExpandAndToString()} 创建成功");
        }

        var errors = results.Where(r => !r.IsSuccess()).Select(r => r.Message);
        return ApiResult.Error($"部分资源创建失败：{string.Join(", ", errors)}");
    }
}

public class CreateResourceCommandValidator : AbstractValidator<CreateResourceCommand>
{
    public CreateResourceCommandValidator(IRepository<Resource> repository)
    {
        RuleFor(m => m.Dtos)
            .NotEmpty()
            .WithMessage("资源数据不能为空")
            .Must(dtos =>
            {
                var codes = dtos.Select(x => new { x.Code, x.ServiceName, x.Type }).ToList();
                return codes.Count == codes.Distinct().Count();
            })
            .WithMessage("批量创建的资源中存在重复的编码、服务名称和类型组合");

        RuleForEach(m => m.Dtos).ChildRules(dto =>
        {
            dto.RuleFor(x => x.Name).NotEmpty().WithMessage("资源名称不能为空");
            dto.RuleFor(x => x.Code).NotEmpty().WithMessage("资源编码不能为空");
            dto.RuleFor(x => x.ServiceName).NotEmpty().WithMessage("服务名称不能为空");
            dto.RuleFor(x => new { x.Code, x.ServiceName, x.Type }).MustAsync(async (tuple, token) =>
            {
                var spec = new ResourceByCodeAndServiceNameAndTypeSpec(tuple.Code, tuple.ServiceName, tuple.Type);
                var flag = await repository.AnyAsync(spec, token);
                return !flag;
            }).WithMessage((request, tuple) => $"资源 {tuple.Code} 在服务 {tuple.ServiceName} 与类型 {tuple.Type} 中已存在");
        });
    }
}

